package org.acghub.mtdb.util;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.*;

public class CachedFileOutputStream extends ByteArrayOutputStream {
    private static final Set<String> FILE_NAME_SET = new HashSet<>();
    private static final Set<File> REMOVE_FILES = new HashSet<>();
    private final Path file;

    public CachedFileOutputStream(File file) throws IOException {
        FILE_NAME_SET.add(file.getAbsolutePath().toLowerCase());
        this.file = Paths.get(file.getCanonicalPath());
    }

    @SuppressWarnings("all")
    private static void doRemoveFile(File file) {
        if (!FILE_NAME_SET.contains(file.getAbsolutePath().toLowerCase())) {
            if (file.isDirectory()) {
                Arrays.stream(Objects.requireNonNull(file.listFiles())).forEach(CachedFileOutputStream::doRemoveFile);
            } else if (file.isFile()) {
                System.err.println("xmlgen: delete file: " + file.getAbsolutePath());
            }
            file.delete();
        }
    }

    public static void removeFiles() {
        REMOVE_FILES.stream().filter(File::exists).forEach(CachedFileOutputStream::doRemoveFile);
        REMOVE_FILES.clear();
    }

    public static void addRemoveFile(File... files) {
        if (files == null) {
            return;
        }
        Collections.addAll(REMOVE_FILES, files);
    }

    private void writeFile() throws IOException {
        Files.write(file, toByteArray(), StandardOpenOption.CREATE, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING);
    }

    @Override
    public void close() throws IOException {
        if (!file.toFile().exists()) {
            writeFile();
        } else if (!Arrays.equals(Files.readAllBytes(file), toByteArray())) {
            System.out.println("xmlgen: modify file: " + file.toAbsolutePath());
            writeFile();
        }
    }
}
